package 多线程;
import java.util.concurrent.locks.*;
/*
 当多个线程共享数据时，会造成线程不安全
 这时候需要线程同步
 同步方法:
 1，同步代码块synchronized(任意对象，通常this){同步执行的操作块}
 2，同步方法 synchronized void method(){同步操作块},方法加上synchronized前缀
 3，lock 方法(更灵活)
    新建ReentrantLock(互斥锁) 对象lock，然后
	lock.lock();
	..同步具体操作....
	lock.unlock();
  使用同步会解决线程不安全问题，但是会带来性能下降，所以同步原则:
  1，代码简洁，把不需要同步操作的代码不要加入同步代码块
  2，不能阻塞，(线程停滞了，导致其他线程无法进行如 inputstream.read())
  3，在持有锁时，不要对其他对象调用方法
 */
public class X05线程同步
{
	public static void main(String[]args)
	{
		MyRunnable5 mr5=new MyRunnable5();
		Thread t1=new Thread(mr5);
		Thread t2=new Thread(mr5);
		t1.setName("网络售票厅");
		t2.setName("实体售票厅");
		t2.setPriority(Thread.MAX_PRIORITY);
		t1.start();//线程不同步会导致同一张票售出两次，
		t2.start();
	}
}

class MyRunnable5 implements Runnable
{
	private static int ticket=10;//共享数据总共十张票
	@Override
	public void run()
	{
		for (int i=0;i < 50;i++)
		{
//			synchronized (this)//代码块式实现同步
//			{
//				if (ticket > 0){
//						ticket--;
//					try
//					{
//						Thread.sleep(100);
//					}
//					catch (InterruptedException e)
//					{}
//					System.out.println(Thread.currentThread().getName() + "卖出一张，剩余：" + ticket + "张");
//				}
//			}
			//method();
			method2();
		}
	}
	//同步方法实现
	private synchronized void method(){
		if (ticket > 0){
			ticket--;
			try
			{
				Thread.sleep(100);
			}
			catch (InterruptedException e)
			{}
			System.out.println(Thread.currentThread().getName() + "卖出一张，剩余：" + ticket + "张");
		}
	}
	
	private ReentrantLock lock=new ReentrantLock();
	private void method2(){
		lock.lock();
		try{//try finally确保了不管任何最后都执行解锁，避免了死锁现象
			if (ticket > 0){
						ticket--;
					try
					{
						Thread.sleep(100);
					}
					catch (InterruptedException e)
					{}
					System.out.println(Thread.currentThread().getName() + "卖出一张，剩余：" + ticket + "张");
				}
		}finally{
			lock.unlock();
		}
		
	}
}

